﻿using System;
using System.Text;

namespace BuddHa.Common.SMUtil.Implementation.V1
{
    using Pool;
    internal class SM2V1PoolDispatch : ModelPool<ISM2Dispatch>, ISM2PoolDispatch
    {
        private readonly IModelPoolOption _modelPoolOption;
        private readonly string _userId;
        private readonly string _publicKey;
        private readonly string _privateKey;
        private readonly SMInEncodingTypes _smInEncodingTypes;

        public SM2V1PoolDispatch(IModelPoolOption modelPoolOption, string userId, string publicKey, string privateKey, SMInEncodingTypes smInEncodingTypes = SMInEncodingTypes.Hex) : base(modelPoolOption)
        {
            _modelPoolOption = modelPoolOption;
            _userId = userId;
            _publicKey = publicKey;
            _privateKey = privateKey;
            _smInEncodingTypes = smInEncodingTypes;
        }

        public void Initialize()
        {
            for (var i = 0; i < _modelPoolOption.MaxSize; i++)
            {
                base.Return(SMBuild.BuildSMDispatch(_userId, _publicKey, _privateKey, SMVersions.V1, _smInEncodingTypes));
            }
        }

        private T DoSMDispatch<T>(Func<ISM2Dispatch, T> func)
        {
            var sm2Dispatch = Rent();
            var result = func.Invoke(sm2Dispatch);
            if (!Return(sm2Dispatch))
            {
                sm2Dispatch.Dispose();
            }
            return result;
        }

        public override ISM2Dispatch Rent()
        {
            var model = base.Rent();
            if (model == null)
            {
                model = SMBuild.BuildSMDispatch(_userId, _publicKey, _privateKey, SMVersions.V1, _smInEncodingTypes);
            }
            return model;
        }

        public string CompressPubKey(string longPK)
        {
            return DoSMDispatch((sm2Dispatch) =>
            {
                return sm2Dispatch.CompressPubKey(longPK);
            });
        }

        public string Decrypt(string data, Encoding encoding = null, SMInEncodingTypes smInEncodingTypes = SMInEncodingTypes.Hex)
        {
            return DoSMDispatch((sm2Dispatch) =>
            {
                return sm2Dispatch.Decrypt(data, encoding, smInEncodingTypes);
            });
        }

        public string Encrypt(string data, Encoding encoding = null, SMInEncodingTypes smInEncodingTypes = SMInEncodingTypes.Hex)
        {
            return DoSMDispatch((sm2Dispatch) =>
            {
                return sm2Dispatch.Encrypt(data, encoding, smInEncodingTypes);
            });
        }

        public string Sign(string data, Encoding encoding = null, SMInEncodingTypes smInEncodingTypes = SMInEncodingTypes.Hex, SMOutEncodingTypes smOutEncodingTypes = SMOutEncodingTypes.Hex)
        {
            return DoSMDispatch((sm2Dispatch) =>
            {
                return sm2Dispatch.Sign(data, encoding, smInEncodingTypes, smOutEncodingTypes);
            });
        }

        public byte[] Sign(byte[] data)
        {
            return DoSMDispatch((sm2Dispatch) =>
            {
                return sm2Dispatch.Sign(data);
            });
        }

        public string UnCompressPubKey(string compressedPK)
        {
            return DoSMDispatch((sm2Dispatch) =>
            {
                return sm2Dispatch.UnCompressPubKey(compressedPK);
            });
        }

        public bool VerifySign(string data, string sign, Encoding encoding = null, SMInEncodingTypes smInEncodingTypes = SMInEncodingTypes.Hex, SMOutEncodingTypes smOutEncodingTypes = SMOutEncodingTypes.Hex)
        {
            return DoSMDispatch((sm2Dispatch) =>
            {
                return sm2Dispatch.VerifySign(data, sign, encoding, smInEncodingTypes, smOutEncodingTypes);
            });
        }

        public bool VerifySign(byte[] data, byte[] sign)
        {
            return DoSMDispatch((sm2Dispatch) =>
            {
                return sm2Dispatch.VerifySign(data, sign);
            });
        }
    }
}
